﻿
namespace Pixels.Core
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;
    using Pixels.ContentTypeItems;
    using Pixels.ContentTypes;
    using Pixels.Core.Extentions;
    using Pixels.ExtentedListItems;
    using Pixels.ListItems;
    using System.Globalization;
    using Pixels.Core;
    using System.Collections;
    using System.Reflection.Emit;
    using System.Linq.Expressions;

    public static class PixelsHelper
    {
        private static IList<IContentType> ContentTypesCache = null;

        private static bool cacheEnabled = false;

        public static string[] PixelsVaildTypes = "Boolean,Byte,Char,DateTime,Decimal,Double,Int32,Int64,Int16,Single,String,Guid".Split(',');

        private static bool VaildPixelsCLRTypes(Type type)
        {
            bool vaild;
            switch (Type.GetTypeCode(type))
            {
                case TypeCode.Boolean:
                    vaild = true;
                    break;
                case TypeCode.Byte:
                    vaild = false;
                    break;
                case TypeCode.Char:
                    vaild = true;
                    break;
                case TypeCode.DBNull:
                    vaild = false;
                    break;
                case TypeCode.DateTime:
                    vaild = true;
                    break;
                case TypeCode.Decimal:
                    vaild = true;
                    break;
                case TypeCode.Double:
                    vaild = true;
                    break;
                case TypeCode.Empty:
                    vaild = true;
                    break;
                case TypeCode.Int16:
                    vaild = true;
                    break;
                case TypeCode.Int32:
                    vaild = true;
                    break;
                case TypeCode.Int64:
                    vaild = true;
                    break;
                case TypeCode.Object:
                    {
                        var genaric = type.GetGenericArguments();

                        if (genaric.Count() > 0)
                        {
                            if (type.GetGenericTypeDefinition() == typeof(Nullable<>))
                            {
                                vaild = true;
                                break;
                            }
                        }

                        vaild = false;
                    }
                    break;
                case TypeCode.SByte:
                    vaild = false;
                    break;
                case TypeCode.Single:
                    vaild = true;
                    break;
                case TypeCode.String:
                    vaild = true;
                    break;
                case TypeCode.UInt16:
                    vaild = true;
                    break;
                case TypeCode.UInt32:
                    vaild = true;
                    break;
                case TypeCode.UInt64:
                    vaild = true;
                    break;
                default:
                    vaild = false;
                    break;
            }
            return vaild;
        }

        public static IContentType RegisterContentType<T>()
        {
            return RegisterContentType<T>(true);
        }

        private static IContentType RegisterContentType<T>(bool updateifExists)
        {
            T _contentTypeInstance = Activator.CreateInstance<T>();

            IContentType _contenttype = null;

            if (CustomAttributeHelper.HasCustomAttribute(_contentTypeInstance, "PixelContentType"))
            {
                _contenttype = new ContentType();
                _contenttype.ContentTypeID = Guid.NewGuid();
                _contenttype.Title = CustomAttributeHelper.GetCustomAttributeConstructorValue(_contentTypeInstance, "PixelContentType", 0);
                _contenttype.Description = CustomAttributeHelper.GetCustomAttributeConstructorValue(_contentTypeInstance, "PixelContentType", 1);

                _contenttype = ContentTypeAdapter.GetInstance().ContentTypeAddEdit(_contenttype, updateifExists);

                foreach (PropertyInfo item in _contentTypeInstance.GetType().GetProperties().Where(p => p.HasCustomAttribute("PixelContentTypeItem")))
                {
                    if (VaildPixelsCLRTypes(item.PropertyType))
                    {
                        IContentTypeItem _contenttypeitem = new ContentTypeItem();

                        _contenttypeitem.ContentTypeItemID = Guid.NewGuid();
                        _contenttypeitem.ItemName = item.Name;
                        _contenttypeitem.DisplayName = item.GetCustomAttributeConstructorValue("PixelContentTypeItem", 0);
                        _contenttypeitem.Size = int.Parse(item.GetCustomAttributeConstructorValue("PixelContentTypeItem", 1));
                        _contenttypeitem.DefaultValue = item.GetCustomAttributeNamedValue("PixelContentTypeItem", "DefaultValue");
                        _contenttypeitem.ContentTypeID = _contenttype.ContentTypeID;
                        _contenttypeitem.Type = item.PropertyType.Name;

                        ContentTypeItemAdapter.GetInstance().ContentItemAddEdit(_contenttypeitem);
                    }
                    else
                    {
                        var genericType = item.PropertyType.GetGenericArguments();

                        if (genericType.Count() == 0)
                        {
                            Type type = item.PropertyType;
                            object subContentType = Activator.CreateInstance(type, null, null);
                            foreach (var subcontenttypeitem in subContentType.GetType().GetProperties().Where(p => p.HasCustomAttribute("PixelContentTypeItem")))
                            {
                                IContentTypeItem _subcontenttypeitem = new ContentTypeItem();

                                _subcontenttypeitem.ContentTypeItemID = Guid.NewGuid();
                                _subcontenttypeitem.ItemName = item.Name + "." + subcontenttypeitem.Name;
                                _subcontenttypeitem.DisplayName = subcontenttypeitem.GetCustomAttributeConstructorValue("PixelContentTypeItem", 0);
                                _subcontenttypeitem.Size = int.Parse(subcontenttypeitem.GetCustomAttributeConstructorValue("PixelContentTypeItem", 1));
                                _subcontenttypeitem.DefaultValue = subcontenttypeitem.GetCustomAttributeNamedValue("PixelContentTypeItem", "DefaultValue");
                                _subcontenttypeitem.ContentTypeID = _contenttype.ContentTypeID;
                                _subcontenttypeitem.Type = item.PropertyType.Name;

                                ContentTypeItemAdapter.GetInstance().ContentItemAddEdit(_subcontenttypeitem);
                            }
                        }
                        else
                        {
                            IContentTypeItem _subcontenttypeitem = new ContentTypeItem();

                            _subcontenttypeitem.ContentTypeItemID = Guid.NewGuid();
                            _subcontenttypeitem.ItemName = item.Name;
                            _subcontenttypeitem.DisplayName = item.GetCustomAttributeConstructorValue("PixelContentTypeItem", 0);
                            _subcontenttypeitem.Size = int.Parse(item.GetCustomAttributeConstructorValue("PixelContentTypeItem", 1));
                            _subcontenttypeitem.DefaultValue = item.GetCustomAttributeNamedValue("PixelContentTypeItem", "DefaultValue");
                            _subcontenttypeitem.ContentTypeID = _contenttype.ContentTypeID;
                            _subcontenttypeitem.Type = item.PropertyType.Name;

                            ContentTypeItemAdapter.GetInstance().ContentItemAddEdit(_subcontenttypeitem);
                        }

                    }
                }
            }

            FlashCache();

            return _contenttype;
        }

        public static IList<IContentType> FetchContentTypes()
        {
            if (ContentTypesCache == null)
            {
                if (cacheEnabled == true)
                    ContentTypesCache = ContentTypeAdapter.GetInstance().ContentTypesFetch();
                else
                    return ContentTypeAdapter.GetInstance().ContentTypesFetch();
            }
            return ContentTypesCache;
        }

        public static IContentType FetchContentType(Guid ContentTypeID)
        {
            if (ContentTypesCache == null)
            {
                ResetCache();
                return ContentTypeAdapter.GetInstance().ContentTypeFetch(ContentTypeID);
            }
            else
                return ContentTypesCache.Where(p => p.ContentTypeID == ContentTypeID).FirstOrDefault();
        }

        public static IContentType FetchContentType<T>()
        {
            string ContentTypeName = CustomAttributeHelper.GetCustomAttributeConstructorValue(Activator.CreateInstance<T>(), "PixelContentType", 0);

            if (ContentTypesCache == null)
            {
                ResetCache();
                return ContentTypeAdapter.GetInstance().ContentTypeFetch(ContentTypeName);
            }
            else
                return ContentTypesCache.Where(p => p.Title.ToLowerInvariant().Trim() == ContentTypeName.ToLowerInvariant().Trim()).FirstOrDefault();
        }

        public static IList<IContentTypeItem> FetchContentItems<T>()
        {
            return ContentTypeItemAdapter.GetInstance().ContentItemsFetchByContentTypeID(FetchContentType<T>().ContentTypeID);
        }

        public static void SaveListItem<T>(T listItem) where T : ListItem, new()
        {
            IContentType contentType = FetchContentType<T>();

            ListItem listitem = new ListItem();

            if (listItem.ListItemID.IsNull())
            {
                listitem.ListItemID = Guid.NewGuid();
            }
            else
            {
                listitem.ListItemID = listItem.ListItemID;
            }

            listitem.ContentTypeID = contentType.ContentTypeID;
            listitem.Title = listItem.Title;
            listitem.Description = listItem.Description;

            ListItemAdapter.GetInstance().ListItemAddEdit(listitem, true);

            foreach (var item in listItem.GetType().GetProperties().Where(p => p.HasCustomAttribute("PixelContentTypeItem")))
            {
                if (item.GetValue(listItem, null) != null)
                {
                    if (VaildPixelsCLRTypes(item.PropertyType))
                    {
                        IExtentedListItem elistItem = new ExtentedListItem();

                        elistItem.ExtentedListItemID = Guid.NewGuid();
                        elistItem.ListItemID = listitem.ListItemID;
                        elistItem.ItemName = item.Name;
                        elistItem.Value = item.GetValue(listItem, null).ToString();

                        elistItem.ContentTypeItemID = ContentTypeItemAdapter.GetInstance().ContentItemFetch(contentType.ContentTypeID, item.Name).ContentTypeItemID;

                        ExtentedListItemAdapter.GetInstance().ExtentedListItemAddEdit(elistItem);
                    }
                    else
                    {
                        var Genarictype = item.PropertyType.GetGenericArguments();

                        if (Genarictype.Count() == 0)
                        {
                            Type type = item.PropertyType;
                            var objsubobject = Convert.ChangeType(item.GetValue(listItem, null), type);

                            foreach (var subextentedlistitem in objsubobject.GetType().GetProperties().Where(p => p.HasCustomAttribute("PixelContentTypeItem")))
                            {
                                if (subextentedlistitem.GetValue(objsubobject, null) != null)
                                {
                                    IExtentedListItem _subextentedlistitem = new ExtentedListItem();

                                    _subextentedlistitem.ExtentedListItemID = Guid.NewGuid();
                                    _subextentedlistitem.ListItemID = listitem.ListItemID;
                                    _subextentedlistitem.ItemName = objsubobject.GetType().Name + "." + subextentedlistitem.Name;
                                    _subextentedlistitem.ContentTypeItemID = ContentTypeItemAdapter.GetInstance().ContentItemFetch(contentType.ContentTypeID, _subextentedlistitem.ItemName).ContentTypeItemID;
                                    _subextentedlistitem.Value = subextentedlistitem.GetValue(objsubobject, null) == null ? "" : subextentedlistitem.GetValue(objsubobject, null).ToString();

                                    ExtentedListItemAdapter.GetInstance().ExtentedListItemAddEdit(_subextentedlistitem);
                                }
                            }
                        }
                        else
                        {
                            IEnumerable extentedlstitems = item.GetValue(listItem, null) as IEnumerable;

                            IEnumerable<IExtentedListItem> dbExtentedListItems = ExtentedListItemAdapter.GetInstance().ExtentedListItemsFetchByListItemID(listitem.ListItemID).Where(p => p.ItemName.Contains(item.GetCustomAttributeConstructorValue("PixelContentTypeItem", 0)));

                            IEnumerable<string> detetedbyUser = dbExtentedListItems.Select(p => p.Value.ToLower()).Except(extentedlstitems.Cast<string>());

                            foreach (var deleteditem in detetedbyUser)
                            {
                                ExtentedListItemAdapter.GetInstance().ExtentedListItemDelete(dbExtentedListItems.Where(p => p.Value.ToLower() == deleteditem).FirstOrDefault().ExtentedListItemID);
                            }

                            int i = 1;

                            foreach (var item2 in extentedlstitems)
                            {
                                IExtentedListItem _subextentedlistitem = new ExtentedListItem();

                                _subextentedlistitem.ExtentedListItemID = Guid.NewGuid();
                                _subextentedlistitem.ListItemID = listitem.ListItemID;
                                _subextentedlistitem.ItemName = item.GetCustomAttributeConstructorValue("PixelContentTypeItem", 0) + i.ToString();
                                _subextentedlistitem.ContentTypeItemID = ContentTypeItemAdapter.GetInstance().ContentItemFetch(contentType.ContentTypeID, item.Name).ContentTypeItemID;
                                _subextentedlistitem.Value = item2.ToString();

                                ExtentedListItemAdapter.GetInstance().ExtentedListItemAddEdit(_subextentedlistitem);
                                i++;
                            }
                        }
                    }
                }
            }

            FlashCache();
        }

        public static T FetchListItem<T>(Guid ListItemID) where T : IListItem
        {
            T listItem = default(T);

            ListItem objListItem = (ListItem)ListItemAdapter.GetInstance().ListItemFetch(ListItemID);

            if (objListItem != null)
            {
                listItem = Activator.CreateInstance<T>();
                listItem.ListItemID = objListItem.ListItemID;
                listItem.Title = objListItem.Title;
                listItem.Description = objListItem.Description;
                listItem.BaseListItemID = objListItem.BaseListItemID;

                ICollection<IExtentedListItem> ExtentedListItems = objListItem.FetchExtentedListItems();

                foreach (PropertyInfo item in listItem.GetType().GetProperties().Where(p => p.HasCustomAttribute("PixelContentTypeItem")))
                {
                    IEnumerable<IExtentedListItem> SelectExtentedListItem = new List<IExtentedListItem>();

                    if (VaildPixelsCLRTypes(item.PropertyType))
                    {
                        SelectExtentedListItem = ExtentedListItems.Where(p => p.ItemName == item.Name);

                        if (SelectExtentedListItem.Count() == 0)
                            continue;

                        item.SetValue(listItem, Convert.ChangeType(SelectExtentedListItem.FirstOrDefault().Value, item.PropertyType), null);

                    }
                    else
                    {
                        var genaric = item.PropertyType.GetGenericArguments();

                        if (genaric.Count() == 0)
                        {
                            SelectExtentedListItem = ExtentedListItems.Where(p => p.ItemName.StartsWith(item.Name));

                            if (SelectExtentedListItem.Count() == 0)
                                continue;

                            Type type = item.PropertyType;
                            var objsubobject = Activator.CreateInstance(type, null, null);
                            item.SetValue(listItem, objsubobject, null);

                            foreach (var subextentedlistitem in objsubobject.GetType().GetProperties().Where(p => p.HasCustomAttribute("PixelContentTypeItem")))
                            {
                                var obj = SelectExtentedListItem.Where(p => p.ItemName == item.Name + "." + subextentedlistitem.Name).FirstOrDefault();
                                if (obj != null)
                                {
                                    genaric = subextentedlistitem.PropertyType.GetGenericArguments();
                                    if (genaric.Count() == 0)
                                        subextentedlistitem.SetValue(objsubobject, Convert.ChangeType(obj.Value, subextentedlistitem.PropertyType), null);
                                    else
                                        subextentedlistitem.SetValue(objsubobject, Convert.ChangeType(obj.Value, Type.GetType(genaric[0].FullName)), null);
                                }
                            }

                        }
                        else
                        {
                            SelectExtentedListItem = ExtentedListItems.Where(p => p.ItemName.StartsWith(item.GetCustomAttributeConstructorValue("PixelContentTypeItem", 0)));

                            if (SelectExtentedListItem.Count() == 0)
                                continue;

                            Type type = item.PropertyType.GetGenericArguments()[0];
                            object objsubobject = null;

                            if (item.PropertyType.GetGenericTypeDefinition() == typeof(List<>))
                            {
                                objsubobject = Activator.CreateInstance(typeof(List<>).MakeGenericType(typeof(string)), null, null);
                                item.SetValue(listItem, objsubobject, null);
                            }

                            foreach (var selectedItem in SelectExtentedListItem)
                            {
                                objsubobject.GetType().GetMethod("Add").Invoke(objsubobject, new[] { selectedItem.Value });
                            }

                        }
                    }
                }
            }

            return listItem;
        }

        public static List<T> FetchListItem<T>(Expression<Func<T, bool>> expression) where T : IListItem
        {
            IContentType contentType = FetchContentType<T>();
            string query = " ContentTypeID = '" + contentType.ContentTypeID + "' AND ";
            Parser(contentType.Title, ref query, expression);

            T listItem = default(T);

            List<T> tlist = new List<T>();

            foreach (var item1 in ListItemAdapter.GetInstance().ListItemsFetchQuery(query))
            {
                IListItem objListItem = item1;

                if (objListItem != null)
                {
                    listItem = Activator.CreateInstance<T>();

                    tlist.Add(listItem);

                    listItem.ListItemID = objListItem.ListItemID;
                    listItem.Title = objListItem.Title;
                    listItem.Description = objListItem.Description;
                    listItem.BaseListItemID = objListItem.BaseListItemID;

                    ICollection<IExtentedListItem> ExtentedListItems = objListItem.FetchExtentedListItems();

                    foreach (PropertyInfo item in listItem.GetType().GetProperties().Where(p => p.HasCustomAttribute("PixelContentTypeItem")))
                    {
                        IEnumerable<IExtentedListItem> SelectExtentedListItem = new List<IExtentedListItem>();

                        if (VaildPixelsCLRTypes(item.PropertyType))
                        {
                            SelectExtentedListItem = ExtentedListItems.Where(p => p.ItemName == item.Name);

                            if (SelectExtentedListItem.Count() == 0)
                                continue;

                            item.SetValue(listItem, Convert.ChangeType(SelectExtentedListItem.FirstOrDefault().Value, item.PropertyType), null);

                        }
                        else
                        {
                            var genaric = item.PropertyType.GetGenericArguments();

                            if (genaric.Count() == 0)
                            {
                                SelectExtentedListItem = ExtentedListItems.Where(p => p.ItemName.StartsWith(item.Name));

                                if (SelectExtentedListItem.Count() == 0)
                                    continue;

                                Type type = item.PropertyType;
                                var objsubobject = Activator.CreateInstance(type, null, null);
                                item.SetValue(listItem, objsubobject, null);

                                foreach (var subextentedlistitem in objsubobject.GetType().GetProperties().Where(p => p.HasCustomAttribute("PixelContentTypeItem")))
                                {
                                    var obj = SelectExtentedListItem.Where(p => p.ItemName == item.Name + "." + subextentedlistitem.Name).FirstOrDefault();
                                    if (obj != null)
                                    {
                                        genaric = subextentedlistitem.PropertyType.GetGenericArguments();
                                        if (genaric.Count() == 0)
                                            subextentedlistitem.SetValue(objsubobject, Convert.ChangeType(obj.Value, subextentedlistitem.PropertyType), null);
                                        else
                                            subextentedlistitem.SetValue(objsubobject, Convert.ChangeType(obj.Value, Type.GetType(genaric[0].FullName)), null);
                                    }
                                }

                            }
                            else
                            {
                                SelectExtentedListItem = ExtentedListItems.Where(p => p.ItemName.StartsWith(item.GetCustomAttributeConstructorValue("PixelContentTypeItem", 0)));

                                if (SelectExtentedListItem.Count() == 0)
                                    continue;

                                Type type = item.PropertyType.GetGenericArguments()[0];
                                object objsubobject = null;

                                if (item.PropertyType.GetGenericTypeDefinition() == typeof(List<>))
                                {
                                    objsubobject = Activator.CreateInstance(typeof(List<>).MakeGenericType(typeof(string)), null, null);
                                    item.SetValue(listItem, objsubobject, null);
                                }

                                foreach (var selectedItem in SelectExtentedListItem)
                                {
                                    objsubobject.GetType().GetMethod("Add").Invoke(objsubobject, new[] { selectedItem.Value });
                                }

                            }
                        }

                    }
                }
            }

            return tlist;
        }



        private static void Parser(string contenttype, ref string query, Expression expression)
        {
            switch (expression.NodeType)
            {

                case ExpressionType.Lambda:
                    LambdaExpression lambdaExpr = (LambdaExpression)expression;
                    Parser(contenttype, ref query, lambdaExpr.Body);
                    break;

                case ExpressionType.Constant:
                    ConstantExpression constExpr = (ConstantExpression)expression;
                    if (Type.GetTypeCode(constExpr.Type) == TypeCode.Int16 || Type.GetTypeCode(constExpr.Type) == TypeCode.Int32 || Type.GetTypeCode(constExpr.Type) == TypeCode.Int64)
                        query += constExpr.Value;
                    else
                        query += " '" + constExpr.Value + "') ";
                    break;

                case ExpressionType.Parameter:
                    ParameterExpression paramExpr = (ParameterExpression)expression;
                    Console.WriteLine(paramExpr.Type.Name);
                    break;

                case ExpressionType.AndAlso:
                case ExpressionType.OrElse:
                case ExpressionType.Equal:
                case ExpressionType.GreaterThan:
                case ExpressionType.GreaterThanOrEqual:
                case ExpressionType.LessThan:
                case ExpressionType.LessThanOrEqual:

                    BinaryExpression binExpr = (BinaryExpression)expression;

                    Parser(contenttype, ref query, binExpr.Left);

                    if (expression.NodeType == ExpressionType.AndAlso)
                    {
                        if (query.Contains("ItemName"))
                        {
                            Console.WriteLine(" OR ");
                            query += " OR ";
                        }
                        else
                        {
                            Console.WriteLine(" AND ");
                            query += " AND ";
                        }
                    }
                    if (expression.NodeType == ExpressionType.OrElse)
                    {
                        Console.WriteLine(" OR ");
                        query += " OR ";
                    }
                    if (expression.NodeType == ExpressionType.Equal)
                    {
                        Console.WriteLine("=");
                        query += " = ";
                    }
                    if (expression.NodeType == ExpressionType.GreaterThan)
                    {
                        Console.WriteLine(">");
                        query += " > ";
                    }
                    if (expression.NodeType == ExpressionType.GreaterThanOrEqual)
                    {
                        Console.WriteLine(">=");
                        query += " >= ";
                    }
                    if (expression.NodeType == ExpressionType.LessThan)
                    {
                        Console.WriteLine("<");
                        query += " < ";
                    }
                    if (expression.NodeType == ExpressionType.LessThanOrEqual)
                    {
                        Console.WriteLine("<=");
                        query += " <= ";
                    }

                    Parser(contenttype, ref query, binExpr.Right);

                    break;

                case ExpressionType.MemberAccess:
                    MemberExpression memberExpr = (MemberExpression)expression;
                    Console.WriteLine(memberExpr.Member.Name);
                    if (memberExpr.Member.Name == "Title" || memberExpr.Member.Name == "Description")
                    {
                        query += "(" + memberExpr.Member.Name;
                    }
                    else
                    {
                        if (memberExpr.Member.DeclaringType.Name == contenttype)
                        {
                            query += " (ItemName = '" + memberExpr.Member.Name + "' AND Value ";
                            Parser(contenttype, ref query, memberExpr.Expression);
                        }
                        else
                        {
                            query += " (ItemName = '" + memberExpr.Member.DeclaringType.Name + "." + memberExpr.Member.Name + "' AND Value ";
                            //Parser(contenttype, ref query, memberExpr.Expression);
                        }
                    }


                    break;
                default:
                    Console.WriteLine();
                    Console.WriteLine("{0} {1}", expression.NodeType, expression.Type.Name);
                    break;
            }

        }

        public static void LoadCache()
        {
            cacheEnabled = true;
            PixelsHelper.FetchContentTypes();
        }

        private static void ResetCache()
        {
            if (cacheEnabled == true)
            {
                PixelsHelper.FetchContentTypes();
            }
        }

        public static void FlashCache()
        {
            ContentTypesCache = null;
            cacheEnabled = false;
        }
    }


}
